﻿// ------------------------------------------------------------------------------
// <copyright file="ServerWrapper.cs" company="MyCompany.com">
//  Copyright © MyCompany.com. All rights reserved.
// </copyright>
// <author>Me</author>
// ------------------------------------------------------------------------------

namespace Terraria
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using BTerrariaMod;
    using BTerrariaMod.Bards;
    using BTerrariaMod.Sugar;
    using Microsoft.Xna.Framework;

    /// <summary>
    /// Wraps the Terraria Server, providing extensibility points for modding.
    /// </summary>
    public class ServerWrapper : Terraria.Main
    {
        /// <summary>
        /// The last status message.
        /// </summary>
        private string lastStatus;

        /// <summary>
        /// The DropBard
        /// </summary>
        private DropBard dropBard;

        /// <summary>
        /// Is Wrapper initialized?
        /// </summary>
        private bool wrapperInitialized = false;

        /// <summary>
        /// The Chest bard
        /// </summary>
        private ChestBard chestBard;

        /// <summary>
        /// The World bard.
        /// </summary>
        private WorldBard worldBard;

        /// <summary>
        /// Initializes a new instance of the <see cref="ServerWrapper"/> class.
        /// </summary>
        /// <param name="args">The args.</param>
        public ServerWrapper(string[] args)
        {
            for (int i = 0; i < (int)args.Length; i++)
            {
                if (args[i].ToLower() == "-config")
                {
                    i++;
                    this.LoadDedConfig(args[i]);
                }

                if (args[i].ToLower() == "-port")
                {
                    i++;
                    try
                    {
                        int num1 = Convert.ToInt32(args[i]);
                        Netplay.serverPort = num1;
                    }
                    catch
                    {
                    }
                }

                if (args[i].ToLower() == "-players" || args[i].ToLower() == "-maxplayers")
                {
                    i++;
                    try
                    {
                        int num2 = Convert.ToInt32(args[i]);
                        SetNetPlayers(num2);
                    }
                    catch
                    {
                    }
                }

                if (args[i].ToLower() == "-pass" || args[i].ToLower() == "-password")
                {
                    i++;
                    Netplay.password = args[i];
                }

                if (args[i].ToLower() == "-world")
                {
                    i++;
                    SetWorld(args[i]);
                }

                if (args[i].ToLower() == "-worldname")
                {
                    i++;
                    SetWorldName(args[i]);
                }

                if (args[i].ToLower() == "-motd")
                {
                    i++;
                    NewMOTD(args[i]);
                }

                if (args[i].ToLower() == "-banlist")
                {
                    i++;
                    Netplay.banFile = args[i];
                }

                if (args[i].ToLower() == "-autoshutdown")
                {
                    autoShut();
                }

                if (args[i].ToLower() == "-secure")
                {
                    Netplay.spamCheck = true;
                }

                if (args[i].ToLower() == "-autocreate")
                {
                    i++;
                    string str1 = args[i];
                    autoCreate(str1);
                }

                if (args[i].ToLower() == "-loadlib")
                {
                    i++;
                    string str2 = args[i];
                    loadLib(str2);
                }
            }

            verboseNetplay = true;

            Console.WriteLine("Starting dedicated server");
            Console.WriteLine("Max recipes is " + Recipe.maxRecipes);
            this.dropBard = new BTerrariaMod.Bards.DropBard(this.AnnounceStatus);
            this.chestBard = new BTerrariaMod.Bards.ChestBard(this.AnnounceStatus);
            this.worldBard = new BTerrariaMod.Bards.WorldBard(this.AnnounceStatus);
        }

        /// <summary>
        /// Processes updates which have occurred in game time.
        /// </summary>
        /// <param name="gameTime">The game time.</param>
        protected override void Update(GameTime gameTime)
        {
            if (this.dropBard != null)
            {
                this.dropBard.AnnounceDrops(item);
            }

            this.SearchOpenChests();

            if (!this.wrapperInitialized && Netplay.anyClients)
            {
                this.InitialUpdate(gameTime);
                this.wrapperInitialized = true;
            }

            this.CheckCommands();
            base.Update(gameTime);
        }

        /// <summary>
        /// Announces the status.
        /// </summary>
        /// <param name="text">The text.</param>
        private void AnnounceStatus(string text)
        {
            if (text != null && text.Length > 0 && text != this.lastStatus)
            {
                Console.WriteLine("Player Names:" + this.ActivePlayers().Select(p => p.name).Aggregate((s1, s2) => s1 + "," + s2));
                Console.WriteLine(DateTime.Now.ToString("yyyy/MM/dd-hh:mm:ss") + "Broadcasting:" + text);
                Messenger.SendToAll(text);
            }
            else
            {
                Console.WriteLine(DateTime.Now.ToString("yyyy/MM/dd-hh:mm:ss") + "Not Broadcasting:" + text);
            }

            this.lastStatus = text;
        }

        /// <summary>
        /// Checks the commands.
        /// </summary>
        private void CheckCommands()
        {
            var commandRequests = player.FirstOrDefault(p => p != null && p.active && p.chatText.StartsWith("/"));
            if (commandRequests == null)
            {
                return;
            }

            this.AnnounceStatus("Found command, attempting to process");
            switch (commandRequests.chatText)
            {
                case "/orbs" :
                    this.worldBard.AnnounceOrbs(Main.tile);
                    break;
                case "/spawn":
                    this.worldBard.AnnounceSpawn(Main.spawnTileX, Main.spawnTileY);
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// Searches the open chests.
        /// </summary>
        private void SearchOpenChests()
        {
            var openChests = this.ActivePlayers().Where(p => p.chest >= 0).Select(p => p.chest);
            foreach (var activePlayer in this.ActivePlayers().Where(p => p.chest >= 0))
            {
                this.chestBard.ChestOpened(activePlayer, chest[activePlayer.chest]);
            }
        }

        /// <summary>
        /// Processes the initial game update.
        /// </summary>
        /// <param name="gameTime">The game time.</param>
        private void InitialUpdate(GameTime gameTime)
        {
            Console.WriteLine("server netmode=" + Main.netMode);
        }

        /// <summary>
        /// Returns the active players with the player index.
        /// </summary>
        /// <returns>The active players with the player index.</returns>
        private IEnumerable<Tuple<int, Player>> ActivePlayersWithIndex()
        {
            return player.JoinIndex().Where(p => p != null && p.Item2 != null && p.Item2.active);
        }

        /// <summary>
        /// Returns the active players.
        /// </summary>
        /// <returns>The active players.</returns>
        private IEnumerable<Player> ActivePlayers()
        {
            return player.Where(p => p != null && p.active == true);
        }
    }
}
